//
//  ZNWBLabel.swift
//  ZNWeibo
//
//  Created by FunctionMaker on 2017/9/20.
//  Copyright © 2017年 FunctionMaker. All rights reserved.
//

import UIKit

class ZNWBLabel: UILabel {
    /// MARK: - TextKit的核心对象
    
    /// 属性文本的存储
    fileprivate lazy var textStorage = NSTextStorage()
    /// `字形`布局管理者
    fileprivate lazy var layoutManager = NSLayoutManager()
    /// 设定文本绘制的范围
    fileprivate lazy var textContainer = NSTextContainer()
    
    /// 更新文本内容
    override var text: String? {
        didSet {
            // 内容变化，textStorage需要做出相应的变化
            prepareTextContent()
        }
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        // 指定绘制文本区域，不涉及路径排除
        textContainer.size = bounds.size
    }
    
    /// MARK: - 构造函数
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        prepareTextRenderSystem()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        prepareTextRenderSystem()
    }
    
    /// 使用TextKit绘制文本
    ///
    /// - Parameter rect: 绘制区域
    override func drawText(in rect: CGRect) {
        // 不调用父类的实现，使用TextKit接管绘制任务
        let range = NSRange(location: 0, length: textStorage.length)
        
        // 绘制背景，要先于绘制文字，否则会覆盖掉文字
        // 在iOS中的绘制工作类似于油画，后绘制的内容会覆盖掉之前绘制的
        layoutManager.drawBackground(forGlyphRange: range, at: CGPoint())
        
        // 从原点开始绘制，可实现Label内容置顶
        // Glyph: 字形
        layoutManager.drawGlyphs(forGlyphRange: range, at: CGPoint())
    }
    
    // MARK: - 交互方法
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        // 1. 获取点击位置
        guard let location = touches.first?.location(in: self) else {
            return
        }
        
        // 2. 获取当前点中文字的索引
        let idx = layoutManager.glyphIndex(for: location, in: textContainer)
        
        // 3. 判断索引是否在urlRanges内，如果是，url改变前景色
        for range in urlRanges ?? [] {
            if NSLocationInRange(idx, range) {
                // 需要高亮
                textStorage.addAttributes(
                    [
                        NSForegroundColorAttributeName: UIColor.purple
                    ], range: range)
                
                // 重新绘制
                setNeedsDisplay()
            }
        }
    }
}

// MARK: - 设置TextKit的核心对象
private extension ZNWBLabel {
    
    /// 准备文本绘制系统
    func prepareTextRenderSystem() {
        // 0. 开启文本交互
        isUserInteractionEnabled = true
        
        // 1. 准备文本内容
        prepareTextContent()
        
        // 2. 设置对象关系
        // 顺次强引用，逆序弱引用
        textStorage.addLayoutManager(layoutManager)
        layoutManager.addTextContainer(textContainer)
    }
    
    func prepareTextContent() {
        if let attributedText = attributedText {
            textStorage.setAttributedString(attributedText)
        } else if let text = text {
            textStorage.setAttributedString(NSAttributedString(string: text))
        } else {
            textStorage.setAttributedString(NSAttributedString(string: ""))
        }
        
        // 遍历url范围，设置url文字的属性
        for range in urlRanges ?? [] {
            textStorage.addAttributes(
                [
                    NSForegroundColorAttributeName: UIColor.orange
                ],
                range: range)
        }
    }
}

// MARK: - 正则表达式，过滤url
private extension ZNWBLabel {
    
    /// 返回文本中的url范围
    var urlRanges: [NSRange]? {
        // 1. url正则表达式
        let pattern = "[a-zA-Z]*://[a-zA-Z0-9/\\.]*"
        
        // 2. 判定
        guard let regx = try? NSRegularExpression(pattern: pattern, options: [])
        else {
            return nil
        }
        
        // 3. 多重匹配
        let matches = regx.matches(in: textStorage.string, options: [], range: NSRange(location: 0, length: textStorage.length))
        
        var ranges = [NSRange]()
        
        for match in matches {
            ranges.append(match.range)
        }
        
        return ranges
    }
}
